package antidestiny.java2dex.compiler;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.Toast;

import com.android.dx.command.Main;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;

import antidestiny.java2dex.FileStructure;
import antidestiny.java2dex.Jing;
import antidestiny.java2dex.R;
import antidestiny.utilib.Aide;
import antidestiny.utilib.io.FileUtils;
import compiler.JavaFile;
import compiler.Jc4a;

/**
 * Created by Hero on 2016/6/25.
 */
public class Compiler {
    public static final String KEY_ERROR_REPORTED = "error reported";

    public interface ICompiler {
        void onCompileFinish(Bundle msg);
    }

    File javaSrcDir;
    File outputDir;
    Context context;
    String outputFileName;
    String libMessage;
    ICompiler mListener;

    public Compiler(File javaSrcDir, String libMessage, File outputDir, String outputFileName, Context context) {
        this.javaSrcDir = javaSrcDir;
        this.outputDir = outputDir;
        this.outputFileName = outputFileName;
        this.context = context;
        this.libMessage = libMessage;
    }

    public void setListener(ICompiler listener) {
        mListener = listener;
    }

    public void compile() {
        Aide.t("编译开始");
        compileThread.get().start();
        Aide.t("编译结束");
    }

    final ThreadLocal<Thread> compileThread;

    {
        compileThread = new ThreadLocal<Thread>() {
            @Override
            protected Thread initialValue() {
                return new Thread() {

                    void errorDialog(final String message, final DialogInterface.OnClickListener listener) {
                        Aide.t("出错" + message);
                        compileHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                                builder.setTitle(getString(R.string.error)).setMessage(message);
                                AlertDialog dialog = builder.setPositiveButton(getString(android.R.string.ok), listener)
                                        .create();
                                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                                    @Override
                                    public void onDismiss(DialogInterface dialog) {
                                        synchronized (compileThread) {
                                            compileThread.notify();
                                        }
                                    }
                                });
                                dialog.show();
                            }
                        });
                        synchronized (compileThread) {
                            try {
                                compileThread.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                warningToast(e.toString());
                            }
                        }
                    }

                    void warningDialog(final String message, final DialogInterface.OnClickListener positiveListener, DialogInterface.OnClickListener negativelistener) {
                        warningDialog(getString(R.string.warning), message, positiveListener, negativelistener);
                    }

                    void warningDialog(final String title, final String message, final DialogInterface.OnClickListener positiveListener, final DialogInterface.OnClickListener negativeListener) {
                        Aide.t("警告:" + message);
                        compileHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                Aide.t("确认提示框");
                                EditText textView = new EditText(context);
                                textView.setHorizontallyScrolling(true);
                                textView.setSingleLine(false);
                                textView.setText(message);
                                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                                builder.setTitle(title)
                                        .setPositiveButton(android.R.string.ok, positiveListener)
                                        .setView(textView)
                                        .setNegativeButton(android.R.string.cancel, negativeListener);
                                AlertDialog dialog = builder.create();
                                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                                    @Override
                                    public void onDismiss(DialogInterface dialog) {
                                        synchronized (compileThread) {
                                            compileThread.notify();
                                        }
                                    }
                                });
                                dialog.show();
                            }
                        });
                        synchronized (compileThread) {
                            try {
                                compileThread.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                warningToast(e.toString());
                            }
                        }
                    }

                    @Override
                    public void run() {
                        //参数检查
                        //java工程文件夹的检查
                        Aide.t("开始检查");
                        File classesOutputDir = new File(outputDir + FileStructure.CLASSES);
                        final Bundle innerClassConnect = new Bundle();
                        PrintStream outPrintStream = null;
                        PrintWriter printWriter;
                        ByteArrayOutputStream outputStream = null;
                        DiagnosticListener<JavaFileObject> diagnosticListener = new DiagnosticListener<JavaFileObject>() {
                            @Override
                            public boolean report(Diagnostic<? extends JavaFileObject> diagnostic) {
                                Aide.t("report");
                                if (diagnostic.getKind().equals(Diagnostic.Kind.ERROR)) {
                                    innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                                }
                                return false;
                            }
                        };
                        if (!javaSrcDir.exists()) {
                            errorDialog(getString(R.string.java_src_not_exist) + javaSrcDir.getAbsolutePath()
                                    , null);
                            innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                            return;
                        } else if (!javaSrcDir.isDirectory()) {
                            errorDialog(javaSrcDir.getAbsolutePath() + "不是一个文件夹！", null);
                            innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                            return;
                        }
                        //输出文件夹的检查
                        if (!outputDir.exists()) {
                            if(null==FileUtils.mkDirsSafely(outputDir, true)){
                                errorDialog("文件夹创建失败",null);
                                innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                                return;
                            }
                        } else if (outputDir.isFile()) {
                            errorDialog("输出文件夹的路径已经被一个文件占用了，改一个吧：" + outputDir, null);
                            innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                            return;
                        }

                        if (classesOutputDir.isFile()) {
                            errorDialog("输出文件夹的路径已经被一个文件占用了，改一个吧：" + classesOutputDir, null);
                            innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                        } else if (!classesOutputDir.exists()) {
                            if(null==FileUtils.mkDirsSafely(classesOutputDir, true)){
                                errorDialog("输出文件夹中classes文件夹创建失败",null);
                                innerClassConnect.putBoolean(KEY_ERROR_REPORTED, true);
                                return;
                            }
                        }

                        //参数检查结束
                        Aide.t("检查结束，正式编译");
                        //开始编译

                        Jc4a jc4a = new Jc4a();
                        jc4a.setOutPutPath(Collections.singletonList(classesOutputDir));
                        jc4a.setDiagnosticListener(diagnosticListener);
                        String message = "";


                        try {
                            System.out.println("编译java文件");
                            outputStream = new ByteArrayOutputStream();
                            outPrintStream = new PrintStream(outputStream, true);
                            printWriter = new PrintWriter(outputStream);
                            System.setOut(outPrintStream);
                            jc4a.setOut(printWriter);
                            Iterable<JavaFile> javaFiles = collectJavaFiles(javaSrcDir);
                            //只有有java文件可编译的时候才去编译
                            if (javaFiles.iterator().hasNext()) {
                                //有lib的话设置classpath
                                if (libMessage != null && libMessage.length() > 0) {
                                    TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(Jing.DIFFRENT_FILE_SEPRATOR);
                                    splitter.setString(libMessage);
                                    ArrayList<File> libfiles = new ArrayList<>();
                                    for (String aSplitter : splitter) {
                                        File libfile = new File(aSplitter);
                                        libfiles.add(libfile);
                                        Aide.t("lib:" + libfile);
                                        FileUtils.copy(libfile, classesOutputDir);
                                    }
                                    jc4a.setClassPath(libfiles);
                                }
                                System.out.println("编译到class文件");
                                jc4a.compile(context.getClassLoader(), new File(Jing.getRtJarPath(context)), collectJavaFiles(javaSrcDir), null);
                                System.out.println("class文件编译结束");
                                //检查编译到class文件的过程是否出错
                                //若出错不可继续编译dex，否则若没有class提供会产生无法接收的错误
                                if (innerClassConnect.getBoolean(KEY_ERROR_REPORTED, false)) {
                                    System.out.println("编译出错了，可能是java工程存在问题。若无法解决，可以联系作者。");
                                    return;
                                }


                                String args[] = {
                                        "--dex", "--output", outputDir.getAbsolutePath() + "/" + outputFileName
                                        , classesOutputDir.toString()
                                };
                                System.out.println("编译class文件到dex");
                                Main.main(args);
                                Aide.t("dex文件编译结束");
                            } else {
                                System.out.println("没有java文件");
                            }
                            System.out.println("编译结束");

                        } catch (Throwable t) {
                            t.printStackTrace();
                            errorDialog(t.toString(), null);
                        } finally {
                            if (outputStream != null) {
                                byte[] outbytes = outputStream.toByteArray();
                                if (outbytes != null) {
                                    message = new String(outbytes);
                                    message = message.replaceAll(" ", "\t");
                                }
                            } else
                                Aide.e("无调试信息！");

                            try {
                                if (outPrintStream != null)
                                    outPrintStream.close();
                            } catch (Throwable t) {
                                t.printStackTrace();
                            }
                            DialogInterface.OnClickListener finalListener = new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (mListener != null)
                                        mListener.onCompileFinish(innerClassConnect);
                                }
                            };
                            warningDialog("结束", "编译完成！请检查调试信息：\n" + message, finalListener, null);
                        }
                    }
                };
            }
        };
    }

    Iterable<JavaFile> collectJavaFiles(File javaProjectDir) {
        ArrayList<File> files = new ArrayList<>();
        files.addAll(Arrays.asList(javaProjectDir.listFiles()));
        ArrayList<JavaFile> javas = new ArrayList<>();
        for (int i = 0; i < files.size(); i++) {
            if (files.get(i).isDirectory()) {
                files.addAll(Arrays.asList(files.get(i).listFiles()));
            } else if (javaFilter.accept(files.get(i))) {
                javas.add(new JavaFile(files.get(i).toURI()));
            }
        }
        return javas;
    }

    final FileFilter javaFilter = new FileFilter() {
        @Override
        public boolean accept(File pathname) {
            String name = pathname.getName();
            if (pathname.isFile()
                    && name.regionMatches(true, name.length() - ".java".length(), ".java", 0, ".java".length())) {
                return true;
            }
            return false;
        }
    };
    final CompileHandler compileHandler = new CompileHandler();

    static class CompileHandler extends Handler {


    }

    String getString(int id) {
        return context.getString(id);
    }

    void warningToast(String s) {
        Toast.makeText(context, s, Toast.LENGTH_LONG).show();
    }
    /** interface ArgChecker {
     String errorMessage();
     boolean check();
     }

     /** //java工程文件检查
     final ArgChecker javaProjectChecker= new ArgChecker() {
    @Override public String errorMessage() {
    return errorMessage[];
    }
    int errorkind;
    String errorMessage[]={
    javaSrcDir+"不存在",
    javaSrcDir+"不是一个文件夹"
    };
    @Override public boolean check() {
    if (!javaSrcDir.exists()){
    return  false;
    }else if (!javaSrcDir.isDirectory()){
    return  false;
    }
    return true;
    }
    };*/

    /** ArrayList<File> searchForMains(File classesDir)throws IOException {
     ArrayList<File> classes=FileUtils.getAllSubFiles(classesDir
     , new FileFilter() {
    @Override public boolean accept(File pathname) {
    return FileUtils.suffixCompare(pathname,".class");
    }
    });
     if (classes!=null)
     for (File c:classes){
     PathClassLoader pathClassLoader=new PathClassLoader();
     pathClassLoader.;
     DexClassLoader dexClassLoader=new DexClassLoader();
     DexFile dexFile=new DexFile()
     }
     DexClassLoader classLoader=new DexClassLoader();
     classLoader.loadClass();
     PathClassLoader pcl;pcl.loadClass();
     }*/


}
